package alibaba.numberprecision;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
 * @author ChangLiang
 * @date 2021/4/1
 */
public class FloatPrecisionTest {

    @Test
    public void test(){
        float a = 20_000_000f;
        float b = 1.0f;
        float c = a + b;
        // c is 2.0E7
        System.out.println("c is " + c);
        // d is 0.0
        float d = c - a;
        System.out.println("d is " + d);
    }

    @Test
    @DisplayName("test2")
    public void test2(){
        float sum = 0.0f;
        for (int i = 0; i < 20_000_000; i++) {
            float x = 1.0f;
            sum += x;
        }
        // sum is 1.6777216E7
        // 最终的结果会是 1600 万左右，而不是 2000 万。这是因为，加到 1600 万之后的加法因为精度丢失都没有了。
        System.out.println("sum is " + sum);
    }

    @Test
    @DisplayName("test")
    public void kahanSummation() {
        float sum = 0.0f;
        float accumulateLoss = 0.0f;
        for (int i = 0; i < 20_000_000; i++) {
            float x = 1.0f;

            // 在每次的计算过程中，都用一次减法，把当前加法计算中损失的精度记录下来
            float currLoss = x - accumulateLoss;

            float currSum = sum + currLoss;

            // 更新loss累计值
            accumulateLoss = (currSum - sum) - currLoss;

            sum = currSum;
        }
        System.out.println("sum is " + sum);
    }
}
